#pragma once
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h>
#include "Log.hpp"
#include "Common.hpp"
using namespace LogModule;
const std::string dev = "/dev/null"; // 将数据往这个文件夹中进行输出，会自动进行丢弃操作的
// 将服务进行守护进程化的服务
void Daemon(int nochdir, int noclose)
{
    // 1、忽略IO、子进程退出等相关的信号
    // 忽略下面两个信号，因为我们不需要处理它们
    signal(SIGPIPE, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);
    // 2、让父进程直接就结束
    if (fork() > 0)
    {
        exit(0);
    }
    // 3、走到这里说明是子进程，子进程成孤儿了，父进程就是1了
    setsid(); // 让当前子进程成为新的会话组长和进程组长
    if(nochdir == 0)//需要进行当前工作路径的修改操作
    {
        chdir("/");
    }

    // 4、到这里依旧可能和显示器，键盘，stdin,stdout,stderr相关的信号，我们需要忽略它们
    // 守护进程，不从键盘输入，也不需要向显示器中打印
    // 方法1：关闭012三个文件描述符---不推荐
    // 方法二：打开dev/null文件，重定向标准输入，标准输出，标准错误到/dev/null


    if (noclose == 0)
    {
        int fd = ::open(dev.c_str(), O_RDWR); // 打开/dev/null文件，以读写的形式

        if (fd < 0) // 说明我们守护进程化失败了
        {
            LOG(LogLevel::FATAL) << "open " << dev << " error";
            exit(OPEN_ERROR); // 打开失败退出
        }
        else // 打开成功了
        {
            // 本来要往显示器上面打印，但是现在要往这个fd文件中输出，这就是重定向操作了、
            dup2(fd, 0); // 将标准输入0，也就是stdin，重定向到/dev/null
            dup2(fd, 1); // 将标准输出1，也就是stdout，重定向到/dev/null
            dup2(fd, 2); // 将标准错误2，也就是stderr，重定向到/dev/null
            close(fd);
        }
    }
}